/*
 * @Author: xiaosihan 
 * @Date: 2023-02-06 15:22:57 
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2024-08-28 22:42:52
 */
import axios from "axios";
import { AdditiveBlending, DoubleSide, MeshBasicMaterial, NoBlending, Object3D, ShaderChunk, ShaderMaterial, Vector2, Vector3 } from "three";
import ThreeBase from "three-base";
import MeshBase from "three-base/MeshBase";
import threeLoader from "three-base/threeLoader";
import loadMesh from "./component3d/loadMesh";
import threeUtils from "three-base/threeUtils";
import { degToRad } from "three/src/math/MathUtils";

/**
 * @class HomeRender
 * @extends {ThreeBase}
 */
class HomeRender extends ThreeBase {

    constructor() {
        super();
    }

    init() {
        super.init();
        this.setCameraType("orthographicCamera");
        this.orthographicCamera.left = -0.5;
        this.orthographicCamera.right = 0.5;
        this.orthographicCamera.bottom = -0.5;
        this.orthographicCamera.top = 0.5;
        this.controls.enabled = false;

        this.resetLookAt({
            center: new Vector3(0, 0, 0),
            position: new Vector3(0, 0, 10)
        });
    }


    setOrthographicCameraSize() {
        const size = threeUtils.getSize(this.mesh);
        const sZoom = (this.size.x / this.size.y);
        const mZoom = (size.x / size.y);

        if (sZoom >= mZoom && mZoom >= 1) {
            this.orthographicCamera.left = -0.5 * (sZoom / mZoom);
            this.orthographicCamera.right = 0.5 * (sZoom / mZoom);
            this.orthographicCamera.bottom = -0.5 / mZoom;
            this.orthographicCamera.top = 0.5 / mZoom;
        } else if (sZoom >= mZoom && mZoom < 1) {
            this.orthographicCamera.left = -0.5 * sZoom;
            this.orthographicCamera.right = 0.5 * sZoom;
            this.orthographicCamera.bottom = -0.5;
            this.orthographicCamera.top = 0.5;
        } else if (sZoom < mZoom && mZoom >= 1) {
            this.orthographicCamera.left = -0.5;
            this.orthographicCamera.right = 0.5;
            this.orthographicCamera.bottom = -0.5 / sZoom;
            this.orthographicCamera.top = 0.5 / sZoom;
        } else if (sZoom < mZoom && mZoom < 1) {
            this.orthographicCamera.left = -0.5 * mZoom;
            this.orthographicCamera.right = 0.5 * mZoom;
            this.orthographicCamera.bottom = -0.5 * (mZoom / sZoom);
            this.orthographicCamera.top = 0.5 * (mZoom / sZoom);
        }

        this.orthographicCamera.updateProjectionMatrix();
    }

    setSize(width: number, height: number): void {
        super.setSize(width, height);
        this.setOrthographicCameraSize();
    }

    mesh = (() => {
        const mesh = new MeshBase();
        mesh.addEventListener("loaded", () => {
            threeUtils.scaleTo(mesh, 1);
            this.setOrthographicCameraSize();
        });
        this.add(mesh);
        return mesh;
    })();

    // 获取 videoMesh
    getVideoMesh() {
        let videoMesh!: Object3D;
        this.mesh.traverse(mesh => {
            if (/^video-\d+-\d+/.test(mesh.name)) {
                videoMesh = mesh;
            }
        });
        return videoMesh;
    }

    // 设置模型
    async setMesh(url: string) {
        this.mesh.loaded = false;
        const object3d = await loadMesh(url);
        MeshBase.models.set(url, object3d);
        await this.mesh.loadModel(url);
    }

    videoShader = new ShaderMaterial({
        uniforms: {
            map: { value: null }, // 贴图纹理
            viewScale: { value: new Vector2(1, 1) } // 视频缩放值
        },
        vertexShader: `
            ${ShaderChunk.common}
            ${ShaderChunk.logdepthbuf_pars_vertex}
            varying vec2 vUv;
            void main() {
                vUv = uv;
                gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
                ${ShaderChunk.logdepthbuf_vertex}
            }
        `,
        fragmentShader: `
            ${ShaderChunk.logdepthbuf_pars_fragment}
            uniform sampler2D map;
            varying vec2 vUv;
            void main() {
                gl_FragColor = texture2D(map, vUv);
                ${ShaderChunk.logdepthbuf_fragment}
            }
        `,
        // blending: AdditiveBlending, // 渲染时不与背景融合计算 直接替换
        side: DoubleSide,
        depthTest: true,
        depthWrite: true,
        transparent: true
    });

    // 设置视频
    async setVidoe(urls: Array<string>) {

        let i = 0;

        await this.mesh.awaitLoaded();

        this.mesh.traverseMesh(mesh => {

            if (/^video-\d+-\d+/.test(mesh.name)) {
                const [screenWidth, screenHeight] = mesh.name.match(/\d+/g) as unknown as [number, number];
                // const screenZoom = screenWidth / screenHeight;
                // const textureZoom = width / height;
                // if (screenZoom > textureZoom) {
                // this.videoShader.uniforms.viewScale.value.set(screenZoom / textureZoom, 1);
                // } else {
                // this.videoShader.uniforms.viewScale.value.set(1, screenZoom / textureZoom);
                // }
                const url = urls[i++];
                if (url) {
                    const vidoeTexture = threeLoader.getTexture(url);
                    (vidoeTexture.image as HTMLVideoElement).muted = false;
                    vidoeTexture.flipY = false;
                    this.videoShader.uniforms.map.value = vidoeTexture;
                    mesh.material = this.videoShader;
                }
            } else {
                mesh.material = new MeshBasicMaterial({
                    side: DoubleSide,
                    map: (mesh.material as MeshBasicMaterial).map
                });
            }
        });
    }


}


const homeRenderer = window.homeRenderer = new HomeRender();

export default homeRenderer;